home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / async11.com / ASYNC.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-06-05  |  57.7 KB  |  1,232 lines

  1. {****************************************************************************}
  2. {*                                                                          *}
  3. {*  ASYNC11 - Interrupt-driven asyncronous communications for Turbo Pascal  *}
  4. {*                  Version 1.1 - Wedensday May 04, 1989                    *}
  5. {*             Copyright (C) 1989, Rising Edge Data Services                *}
  6. {*                         Author : Mark Schultz                            *}
  7. {*                                                                          *}
  8. {*--------------------------------------------------------------------------*}
  9. {*                                                                          *}
  10. {*  The routines that follow comprise a Turbo Pascal UNIT that will fully   *}
  11. {*  impliment interrupt-driven serial communications on a fully PC-compat-  *}
  12. {*  able computer (those machines that use the 8250 or equivalent UART      *}
  13. {*  mapped at the standard addresses).  Full simultaneous buffering for     *}
  14. {*  both input and output with variable buffer sizes for each port is       *}
  15. {*  provided.  Unlike many other libraries of a similar nature, up to 4     *}
  16. {*  ports may be active simultaneously (easily modified for more).          *}
  17. {*                                                                          *}
  18. {*  For further details, consult the procedure/function headers within the  *}
  19. {*  program or check the accompanying ASYNC11.DOC file.                     *}
  20. {*                                                                          *}
  21. {*  This product is copyrighted (C) 1988 by Rising Edge Software, Inc. and  *}
  22. {*  it's author, Mark Schultz.  Permission is granted for non-commercial    *}
  23. {*  use and distribution.  Refer to the file ASYNC11.DOC for details.       *}
  24. {*                                                                          *}
  25. {*  Version History:                                                        *}
  26. {*                                                                          *}
  27. {*  V1.1 - Corrected errors that dealt with the handling of the 8259.  Also *}
  28. {*         added compensation for "bugs" that are present in some 8250's    *}
  29. {*         and equivalent gate arrays (Thanks to Ralph Schraven, Toshiba    *}
  30. {*         Europa GmbH for tracking these problems down).                   *}
  31. {*                                                                          *}
  32. {*  V1.0 - First release                                                    *}
  33. {*                                                                          *}
  34. {*--------------------------------------------------------------------------*}
  35. {*                                                                          *}
  36. {*  Status byte definition (C_Status):                                      *}
  37. {*                                                                          *}
  38. {*  7   6   5   4   3   2   1   0                                           *}
  39. {*  |   |   |   |   |   |   |   |____ Input buffer empty                    *}
  40. {*  |   |   |   |   |   |   |________ Input buffer full                     *}
  41. {*  |   |   |   |   |   |____________ Output buffer empty                   *}
  42. {*  |   |   |   |   |________________ Output buffer full                    *}
  43. {*  |   |   |   |____________________ Input buffer overflow                 *}
  44. {*  |   |   |________________________ Output buffer overflow                *}
  45. {*  |   |____________________________ Hard handshake active (xmit stopped)  *}
  46. {*  |________________________________ Soft handshake active (xmit stopped)  *}
  47. {*                                                                          *}
  48. {*  Control byte definition (C_Ctrl):                                       *}
  49. {*                                                                          *}
  50. {*  7   6   5   4   3   2   1   0                                           *}
  51. {*  |   |   |   |   |   |   |   |____ Enable RTS handshake                  *}
  52. {*  |   |   |   |   |   |   |________ Enable CTS handshake                  *}
  53. {*  |   |   |   |   |   |____________ Enable software handshake             *}
  54. {*  |   |   |   |   |________________                                       *}
  55. {*  |   |   |   |____________________                                       *}
  56. {*  |   |   |________________________                                       *}
  57. {*  |   |____________________________                                       *}
  58. {*  |________________________________                                       *}
  59. {*                                                                          *}
  60. {****************************************************************************}
  61.  
  62. {$R-,V-,B-}
  63. {$M 12400,9001,10000}
  64. Unit ASYNC;
  65.  
  66. INTERFACE
  67.  
  68. {----------------------------------------------------------------------------}
  69.  
  70. Const
  71.   C_MinBaud = 50;
  72.   C_MaxBaud = 115200;
  73.  
  74.   { Base port addresses & interrupt usage }
  75.  
  76.   C_MaxPort = 4;
  77.   C_MaxCom : Byte = C_MaxPort;
  78.   C_PortAddr : Array[1..C_MaxPort] Of Word = ($03F8,$02F8,$03E8,$02E8);
  79.   C_PortInt : Array[1..C_MaxPort] Of Byte = (4,3,4,3);
  80.  
  81. {----------------------------------------------------------------------------}
  82.  
  83. Type
  84.   C_PointerArray = Array[1..C_MaxPort] Of Pointer;
  85.   C_WordArray = Array[1..C_MaxPort] Of Word;
  86.   C_ByteArray = Array[1..C_MaxPort] Of Byte;
  87.   C_CharArray = Array[1..C_MaxPort] Of Char;
  88.   C_BooleanArray = Array[1..C_MaxPort] Of Boolean;
  89.  
  90. {----------------------------------------------------------------------------}
  91.  
  92. Var
  93.   C_InBufPtr,C_OutBufPtr : C_PointerArray;    { Input/output buffer pointers }
  94.   C_InHead,C_OutHead     : C_WordArray;       { Input/output head pointers }
  95.   C_InTail,C_OutTail     : C_WordArray;       { Input/output tail pointers }
  96.   C_InSize,C_OutSize     : C_WordArray;       { Input/output buffer sizes }
  97.   C_RTSOn,C_RTSOff       : C_WordArray;       { RTS assert/drop buffer points }
  98.   C_StartChar,C_StopChar : C_CharArray;       { Soft hndshake start/stop char }
  99.   C_Status,C_Ctrl        : C_ByteArray;       { STATUS and CONTROL registers }
  100.   C_XL3Ptr               : C_ByteArray;
  101.   C_PortOpen             : C_BooleanArray;    { Port open/close flags }
  102.   C_Temp : Word;                              { Used for debugging }
  103.  
  104. {----------------------------------------------------------------------------}
  105.  
  106. { Procedure headers - required for UNITization }
  107.  
  108. Function  ComReadCh(ComPort:Byte) : Char;
  109. Function  ComReadChW(ComPort:Byte) : Char;
  110. Procedure ComWriteCh(ComPort:Byte; Ch:Char);
  111. Procedure ComWriteChW(ComPort:Byte; Ch:Char);
  112. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  113. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  114. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  115. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  116. Function  CTSStat(ComPort:Byte) : Boolean;
  117. Function  DSRStat(ComPort:Byte) : Boolean;
  118. Function  RIStat(ComPort:Byte) : Boolean;
  119. Function  DCDStat(ComPort:Byte) : Boolean;
  120. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  121. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  122. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  123. Procedure ClearCom(ComPort:Byte; IO:Char);
  124. Function  ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  125. Procedure ComWaitForClear(ComPort:Byte);
  126. Procedure ComWrite(ComPort:Byte; St:String);
  127. Procedure ComWriteln(ComPort:Byte; St:String);
  128. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  129. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  130. Function  ComExist(ComPort:Byte) : Boolean;
  131. Function  ComTrueBaud(Baud:Longint) : Real;
  132. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  133. Function  OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  134. Procedure CloseCom(ComPort:Byte);
  135. Procedure CloseAllComs;
  136.  
  137. {----------------------------------------------------------------------------}
  138.  
  139. IMPLEMENTATION
  140.  
  141. Uses DOS,CRT;
  142.  
  143. {$L C:\pascal\forum\ASYNC.OBJ}
  144.  
  145. Const
  146.   C_IER = 1;                           { 8250 register offsets }
  147.   C_IIR = 2;
  148.   C_LCR = 3;
  149.   C_MCR = 4;
  150.   C_LSR = 5;
  151.   C_MSR = 6;
  152.   C_SCR = 7;
  153.  
  154. Var
  155.   C_OldINTVec : C_PointerArray;        { Storage for old hardware INT vectors }
  156.   X : Byte;                            { Used by initialization code }
  157.  
  158. {****************************************************************************}
  159. {*                                                                          *}
  160. {*  Procedure INT_Handler; External;                                        *}
  161. {*                                                                          *}
  162. {*  Hardware interrupts 3 and 4 (vectors $0B and $0C) are pointed to        *}
  163. {*  this routine.  It is for internal use only and should NOT be called     *}
  164. {*  directly.  Written in assembly language (see ASYNC11.ASM).              *}
  165. {*                                                                          *}
  166. {****************************************************************************}
  167.  
  168. Procedure INT_Handler; External;
  169.  
  170. {****************************************************************************}
  171. {*                                                                          *}
  172. {*  Procedure ComReadCh(ComPort:Byte) : Char; External;                     *}
  173. {*                                                                          *}
  174. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  175. {*                                                                          *}
  176. {*  Returns character from input buffer of specified port.  If the buffer   *}
  177. {*  is empty, the port # invalid or not opened, a Chr(0) is returned.       *}
  178. {*  Written in assembly language for best possible speed (see ASYNC11.ASM)  *}
  179. {*                                                                          *}
  180. {****************************************************************************}
  181.  
  182. Function ComReadCh(ComPort:Byte) : Char; External;
  183.  
  184. {****************************************************************************}
  185. {*                                                                          *}
  186. {*  Function ComReadChW(ComPort:Byte) : Char; External;                     *}
  187. {*                                                                          *}
  188. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  189. {*                                                                          *}
  190. {*  Works like ComReadCh, but will wait until at least 1 character is       *}
  191. {*  present in the specified input buffer before exiting.  Thus, ComReadChW *}
  192. {*  works much like the ReadKey predefined function.  Written in assembly   *}
  193. {*  language to maximize performance (see ASYNC11.ASM)                      *}
  194. {*                                                                          *}
  195. {****************************************************************************}
  196.  
  197. Function ComReadChW(ComPort:Byte) : Char; External;
  198.  
  199. {****************************************************************************}
  200. {*                                                                          *}
  201. {*  Procedure ComWriteCh(ComPort:Byte; Ch:Char); External                   *}
  202. {*                                                                          *}
  203. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  204. {*  Ch:Char       ->  Character to send                                     *}
  205. {*                                                                          *}
  206. {*  Places the character [Ch] in the transmit buffer of the specified port. *}
  207. {*  If the port specified is not open or nonexistent, or if the buffer is   *}
  208. {*  filled, the character is discarded.  Written in assembly language to    *}
  209. {*  maximize performance (see ASYNC11.ASM)                                  *}
  210. {*                                                                          *}
  211. {****************************************************************************}
  212.  
  213. Procedure ComWriteCh(ComPort:Byte; Ch:Char); External;
  214.  
  215. {****************************************************************************}
  216. {*                                                                          *}
  217. {*  Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;                 *}
  218. {*                                                                          *}
  219. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  220. {*  Ch:Char       ->  Character to send                                     *}
  221. {*                                                                          *}
  222. {*  Works as ComWriteCh, but will wait until at least 1 free position is    *}
  223. {*  available in the output buffer before attempting to place the character *}
  224. {*  [Ch] in it.  Allows the programmer to send characters without regard to *}
  225. {*  available buffer space.  Written in assembly language to maximize       *}
  226. {*  performance (see ASYNC11.ASM)                                           *}
  227. {*                                                                          *}
  228. {****************************************************************************}
  229.  
  230. Procedure ComWriteChW(ComPort:Byte; Ch:Char); External;
  231.  
  232. {****************************************************************************}
  233. {*                                                                          *}
  234. {*  Procedure SetDTR(ComPort:Byte; Assert:Boolean);                         *}
  235. {*                                                                          *}
  236. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  237. {*                      Call ignored if out-of-range                        *}
  238. {*  Assert:Boolean  ->  DTR assertion flag (TRUE to assert DTR)             *}
  239. {*                                                                          *}
  240. {*  Provides a means to control the port's DTR (Data Terminal Ready) signal *}
  241. {*  line.  When [Assert] is TRUE, the DTR line is placed in the "active"    *}
  242. {*  state, signalling to a remote system that the host is "on-line"         *}
  243. {*  (although not nessesarily ready to receive data - see SetRTS).          *}
  244. {*                                                                          *}
  245. {****************************************************************************}
  246.  
  247. Procedure SetDTR(ComPort:Byte; Assert:Boolean);
  248.  
  249. Var
  250.   P,X : Integer;
  251.  
  252. Begin
  253.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  254.   P := C_PortAddr[ComPort];
  255.  
  256.   X := Port[P+C_MCR];
  257.   If Assert Then
  258.     X := X Or $01
  259.   Else
  260.     X := X And $FE;
  261.   Port[P+C_MCR] := X;
  262. End;
  263.  
  264. {****************************************************************************}
  265. {*                                                                          *}
  266. {*  Procedure SetRTS(ComPort:Byte; Assert:Boolean)                          *}
  267. {*                                                                          *}
  268. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  269. {*                      Call ignored if out-of-range                        *}
  270. {*  Assert:Boolean  ->  RTS assertion flag (Set TRUE to assert RTS)         *}
  271. {*                                                                          *}
  272. {*  SetRTS allows a program to manually control the Request-To-Send (RTS)   *}
  273. {*  signal line.  If RTS handshaking is disabled (see C_Ctrl definition     *}
  274. {*  and the the SetRTSMode procedure), this procedure may be used.  SetRTS  *}
  275. {*  should NOT be used if RTS handshaking is enabled.                       *}
  276. {*                                                                          *}
  277. {****************************************************************************}
  278.  
  279. Procedure SetRTS(ComPort:Byte; Assert:Boolean);
  280.  
  281. Var
  282.   P,X : Integer;
  283.  
  284. Begin
  285.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  286.   P := C_PortAddr[ComPort];
  287.  
  288.   X := Port[P+C_MCR];
  289.   If Assert Then
  290.     X := X Or $02
  291.   Else
  292.     X := X And $FD;
  293.   Port[P+C_MCR] := X;
  294. End;
  295.  
  296. {****************************************************************************}
  297. {*                                                                          *}
  298. {*  Procedure SetOUT1(ComPort:Byte; Assert:Boolean)                         *}
  299. {*                                                                          *}
  300. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  301. {*                      Call ignored if out-of-range                        *}
  302. {*  Assert:Boolean  ->  OUT1 assertion flag (set TRUE to assert OUT1 line)  *}
  303. {*                                                                          *}
  304. {*  SetOUT1 is provided for reasons of completeness only, since the         *}
  305. {*  standard PC/XT/AT configurations do not utilize this control signal.    *}
  306. {*  If [Assert] is TRUE, the OUT1 signal line on the 8250 will be set to a  *}
  307. {*  LOW logic level (inverted logic).  The OUT1 signal is present on pin 34 *}
  308. {*  of the 8250 (but not on the port itself).                               *}
  309. {*                                                                          *}
  310. {****************************************************************************}
  311.  
  312. Procedure SetOUT1(ComPort:Byte; Assert:Boolean);
  313.  
  314. Var
  315.   P,X : Integer;
  316.  
  317. Begin
  318.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  319.   P := C_PortAddr[ComPort];
  320.  
  321.   X := Port[P+C_MCR];
  322.   If Assert Then
  323.     X := X Or $04
  324.   Else
  325.     X := X And $FB;
  326.   Port[P+C_MCR] := X;
  327. End;
  328.  
  329. {****************************************************************************}
  330. {*                                                                          *}
  331. {*  Procedure SetOUT2(ComPort:Byte; Assert:Boolean)                         *}
  332. {*                                                                          *}
  333. {*  ComPort:Byte    ->  Port # to use (1 - C_MaxCom)                        *}
  334. {*                      Call ignored if out-of-range                        *}
  335. {*  Assert:Boolean  ->  OUT2 assertion flag (set TRUE to assert OUT2 line)  *}
  336. {*                                                                          *}
  337. {*  The OUT2 signal line, although not available on the port itself, is     *}
  338. {*  used to gate the 8250 <INTRPT> (interrupt) line and thus acts as a      *}
  339. {*  redundant means of controlling 8250 interrupts.  When [Assert] is TRUE, *}
  340. {*  the /OUT2 line on the 8250 is lowered, which allows the passage of the  *}
  341. {*  <INTRPT> signal through a gating arrangement, allowing the 8250 to      *}
  342. {*  generate interrupts.  Int's can be disabled bu unASSERTing this line.   *}
  343. {*                                                                          *}
  344. {****************************************************************************}
  345.  
  346. Procedure SetOUT2(ComPort:Byte; Assert:Boolean);
  347.  
  348. Var
  349.   P,X : Integer;
  350.  
  351. Begin
  352.   If (ComPort<1) Or (ComPort>C_MaxCom) Then Exit;
  353.   P := C_PortAddr[ComPort];
  354.  
  355.   X := Port[P+C_MCR];
  356.   If Assert Then
  357.     X := X Or $08
  358.   Else
  359.     X := X And $F7;
  360.   Port[P+C_MCR] := X;
  361. End;
  362.  
  363. {****************************************************************************}
  364. {*                                                                          *}
  365. {*  Function CTSStat(ComPort:Byte) : Boolean                                *}
  366. {*                                                                          *}
  367. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  368. {*                    Call ignored if out-of-range                          *}
  369. {*  Returns status of Clear-To-Send line (TRUE if CTS asserted)             *}
  370. {*                                                                          *}
  371. {*  CTSStat provides a means to interrogate the Clear-To-Send hardware      *}
  372. {*  handshaking line.  In a typical arrangement, when CTS is asserted, this *}
  373. {*  signals the host (this computer) that the receiver is ready to accept   *}
  374. {*  data (in contrast to the DSR line, which signals the receiver as        *}
  375. {*  on-line but not nessesarily ready to accept data).  An automated mech-  *}
  376. {*  ansim (see CTSMode) is provided to do this, but in cases where this is  *}
  377. {*  undesirable or inappropriate, the CTSStat function can be used to int-  *}
  378. {*  terrogate this line manually.                                           *}
  379. {*                                                                          *}
  380. {****************************************************************************}
  381.  
  382. Function CTSStat(ComPort:Byte) : Boolean;
  383.  
  384. Begin
  385.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  386.     CTSStat := False
  387.   Else
  388.     CTSStat := (Port[C_PortAddr[ComPort]+C_MSR] And $10) > 0;
  389. End;
  390.  
  391. {****************************************************************************}
  392. {*                                                                          *}
  393. {*  Function DSRStat(ComPort:Byte) : Boolean                                *}
  394. {*                                                                          *}
  395. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  396. {*                    Call ignored if out-of-range                          *}
  397. {*  Returns status of Data Set Ready (DSR) signal line.                     *}
  398. {*                                                                          *}
  399. {*  The Data Set Ready (DSR) line is typically used by a remote station     *}
  400. {*  to signal the host system that it is on-line (although not nessesarily  *}
  401. {*  ready to receive data yet - see CTSStat).  A remote station has the DSR *}
  402. {*  line asserted if DSRStat returns TRUE.                                  *}
  403. {*                                                                          *}
  404. {****************************************************************************}
  405.  
  406. Function DSRStat(ComPort:Byte) : Boolean;
  407.  
  408. Begin
  409.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  410.     DSRStat := False
  411.   Else
  412.     DSRStat := (Port[C_PortAddr[ComPort]+C_MSR] And $20) > 0;
  413. End;
  414.  
  415. {****************************************************************************}
  416. {*                                                                          *}
  417. {*  Function RIStat(ComPort:Byte) : Boolean                                 *}
  418. {*                                                                          *}
  419. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  420. {*                    Call ignored if out-of-range                          *}
  421. {*                                                                          *}
  422. {*  Returns the status of the Ring Indicator (RI) line.  This line is       *}
  423. {*  typically used only by modems, and indicates that the modem has detect- *}
  424. {*  ed an incoming call if RIStat returns TRUE.                             *}
  425. {*                                                                          *}
  426. {****************************************************************************}
  427.  
  428. Function RIStat(ComPort:Byte) : Boolean;
  429.  
  430. Begin
  431.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  432.     RIStat := False
  433.   Else
  434.     RIStat := (Port[C_PortAddr[ComPort]+C_MSR] And $40) > 0;
  435. End;
  436.  
  437. {****************************************************************************}
  438. {*                                                                          *}
  439. {*  Function DCDStat(ComPort:Byte) : Boolean                                *}
  440. {*                                                                          *}
  441. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  442. {*                    Call ignored if out-of-range                          *}
  443. {*                                                                          *}
  444. {*  Returns the status of the Data Carrier Detect (DCD) line from the rem-  *}
  445. {*  ote device, typically a modem.  When asserted (DCDStat returns TRUE),   *}
  446. {*  the modem indicates that it has successfuly linked with another modem   *}
  447. {*  device at another site.                                                 *}
  448. {*                                                                          *}
  449. {****************************************************************************}
  450.  
  451. Function DCDStat(ComPort:Byte) : Boolean;
  452.  
  453. Begin
  454.   If (ComPort<1) Or (ComPort>C_MaxCom) Then
  455.     DCDStat := False
  456.   Else
  457.     DCDStat := (Port[C_PortAddr[ComPort]+C_MSR] And $80) > 0;
  458. End;
  459.  
  460. {****************************************************************************}
  461. {*                                                                          *}
  462. {*  Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word)     *}
  463. {*                                                                          *}
  464. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  465. {*                    Request ignored if out of range or unopened.          *}
  466. {*  Mode:Boolean  ->  TRUE to enable automatic RTS handshake                *}
  467. {*  RTSOn:Word    ->  Buffer-usage point at which the RTS line is asserted  *}
  468. {*  RTSOff:Word   ->  Buffer-usage point at which the RTS line is dropped   *}
  469. {*                                                                          *}
  470. {*  SetRTSMode enables or disables automated RTS handshaking.  If [MODE] is *}
  471. {*  TRUE, automated RTS handshaking is enabled.  If enabled, the RTS line   *}
  472. {*  will be DROPPED when the # of buffer bytes used reaches or exceeds that *}
  473. {*  of [RTSOff].  The RTS line will then be re-asserted when the buffer is  *}
  474. {*  emptied down to the [RTSOn] usage point.  If either [RTSOn] or [RTSOff] *}
  475. {*  exceeds the input buffer size, they will be forced to (buffersize-1).   *}
  476. {*  If [RTSOn] > [RTSOff] then [RTSOn] will be the same as [RTSOff].        *}
  477. {*  The actual handshaking control is located in the interrupt driver for   *}
  478. {*  the port (see ASYNC11.ASM).                                             *}
  479. {*                                                                          *}
  480. {****************************************************************************}
  481.  
  482. Procedure SetRTSMode(ComPort:Byte; Mode:Boolean; RTSOn,RTSOff:Word);
  483.  
  484. Var
  485.   X : Byte;
  486.  
  487. Begin
  488.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  489.  
  490.   X := C_Ctrl[ComPort];
  491.   If Mode Then X := X Or $01 Else X := X And $FE;
  492.   C_Ctrl[ComPort] := X;
  493.  
  494.   If Mode Then
  495.     Begin
  496.       If (RTSOff >= C_InSize[ComPort]) Then RTSOff := C_InSize[ComPort] - 1;
  497.       If (RTSOn > RTSOff) Then RTSOff := RTSOn;
  498.       C_RTSOn[ComPort] := RTSOn;
  499.       C_RTSOff[ComPort] := RTSOff;
  500.     End;
  501. End;
  502.  
  503. {****************************************************************************}
  504. {*                                                                          *}
  505. {*  Procedure SetCTSMode(ComPort:Byte; Mode:Boolean)                        *}
  506. {*                                                                          *}
  507. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  508. {*                    Request ignored if out of range or unopened.          *}
  509. {*  Mode:Boolean  ->  Set to TRUE to enable automatic CTS handshake.        *}
  510. {*                                                                          *}
  511. {*  SetCTSMode allows the enabling or disabling of automated CTS handshak-  *}
  512. {*  ing.  If [Mode] is TRUE, CTS handshaking is enabled, which means that   *}
  513. {*  if the remote drops the CTS line, the transmitter will be disabled      *}
  514. {*  until the CTS line is asserted again.  Automatic handshake is disabled  *}
  515. {*  if [Mode] is FALSE.  CTS handshaking and "software" handshaking (pro-   *}
  516. {*  vided by the SoftHandshake procedure) ARE compatable and may be used    *}
  517. {*  in any combination.  The actual logic for CTS handshaking is located    *}
  518. {*  in the communications interrupt driver (see ASYNC11.ASM).               *}
  519. {*                                                                          *}
  520. {****************************************************************************}
  521.  
  522. Procedure SetCTSMode(ComPort:Byte; Mode:Boolean);
  523.  
  524. Var
  525.   X : Byte;
  526.  
  527. Begin
  528.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  529.  
  530.   X := C_Ctrl[ComPort];
  531.   If Mode Then X := X Or $02 Else X := X And $FD;
  532.   C_Ctrl[ComPort] := X;
  533. End;
  534.  
  535. {****************************************************************************}
  536. {*                                                                          *}
  537. {*  Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char)    *}
  538. {*                                                                          *}
  539. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  540. {*                    Request ignored if out of range or unopened.          *}
  541. {*  Mode:Boolean  ->  Set to TRUE to enable transmit software handshake     *}
  542. {*  Start:Char    ->  START control character (usually ^Q)                  *}
  543. {*                    Defaults to ^Q if character passed is >= <Space>      *}
  544. {*  Stop:Char     ->  STOP control character (usually ^S)                   *}
  545. {*                    Defaults to ^S if character passed is >= <Space>      *}
  546. {*                                                                          *}
  547. {*  SoftHandshake controls the usage of "Software" (control-character)      *}
  548. {*  handshaking on transmission.  If "software handshake" is enabled        *}
  549. {*  ([Mode] is TRUE), transmission will be halted if the character in       *}
  550. {*  [Stop] is received.  Transmission is re-enabled if the [Start] char-    *}
  551. {*  acter is received.  Both the [Start] and [Stop] characters MUST be      *}
  552. {*  CONTROL characters (i.e. Ord(Start) and Ord(Stop) must both be < 32).   *}
  553. {*  Also, <Start> and <Stop> CANNOT be the same character.  If either one   *}
  554. {*  of these restrictions are violated, the defaults (^Q for <Start> and ^S *}
  555. {*  for <Stop>) will be used.  Software handshaking control is implimented  *}
  556. {*  within the communications interrupt driver (see ASYNC11.ASM).           *}
  557. {*                                                                          *}
  558. {****************************************************************************}
  559.  
  560. Procedure SoftHandshake(ComPort:Byte; Mode:Boolean; Start,Stop:Char);
  561.  
  562. Var
  563.   X : Byte;
  564.  
  565. Begin
  566.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  567.  
  568.   X := C_Ctrl[ComPort];
  569.   If Mode Then
  570.     Begin
  571.       X := X Or $04;
  572.       If Start=Stop Then Begin Start := ^Q; Stop := ^S; End;
  573.       If Start>#32 Then Start := ^Q;
  574.       If Stop>#32 Then Stop := ^S;
  575.       C_StartChar[ComPort] := Start;
  576.       C_StopChar[ComPort] := Stop;
  577.     End
  578.   Else
  579.     X := X And $FB;
  580.   C_Ctrl[ComPort] := X;
  581. End;
  582.  
  583. {****************************************************************************}
  584. {*                                                                          *}
  585. {*  Procedure ClearCom(ComPort:Byte); IO:Char)                              *}
  586. {*                                                                          *}
  587. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  588. {*                    Request ignored if out of range or unopened.          *}
  589. {*  IO:Char       ->  Action code; I=Input, O=Output, B=Both                *}
  590. {*                    No action taken if action code unrecognized.          *}
  591. {*                                                                          *}
  592. {*  ClearCom allows the user to completely clear the contents of either     *}
  593. {*  the input (receive) and/or output (transmit) buffers.  The "action      *}
  594. {*  code" passed in <IO> determines if the input (I) or output (O) buffer   *}
  595. {*  is cleared.  Action code (B) will clear both buffers.  This is useful   *}
  596. {*  if you wish to cancel a transmitted message or ignore part of a         *}
  597. {*  received message.                                                       *}
  598. {*                                                                          *}
  599. {****************************************************************************}
  600.  
  601. Procedure ClearCom(ComPort:Byte; IO:Char);
  602.  
  603. Var
  604.   P,X : Word;
  605.  
  606. Begin
  607.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  608.  
  609.   IO := Upcase(IO);
  610.   P := C_PortAddr[ComPort];
  611.  
  612.   Inline($FA);
  613.   If (IO='I') Or (IO='B') Then
  614.     Begin
  615.       C_InHead[ComPort] := 0;
  616.       C_InTail[ComPort] := 0;
  617.       C_Status[ComPort] := (C_Status[ComPort] And $EC) Or $01;
  618.       X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  619.     End;
  620.   If (IO='O') Or (IO='B') Then
  621.     Begin
  622.       C_OutHead[ComPort] := 0;
  623.       C_OutTail[ComPort] := 0;
  624.       C_Status[ComPort] := (C_Status[ComPort] And $D3) Or $04;
  625.       X := Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  626.     End;
  627.   Inline($FB);
  628. End;
  629.  
  630. {****************************************************************************}
  631. {*                                                                          *}
  632. {*  Procedure ComBufferLeft(ComPort:Byte; IO:Char) : Word                   *}
  633. {*                                                                          *}
  634. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  635. {*                    Returns 0 if Port # invalid or unopened.              *}
  636. {*  IO:Char       ->  Action code; I=Input, O=Output                        *}
  637. {*                    Returns 0 if action code unrecognized.                *}
  638. {*                                                                          *}
  639. {*  ComBufferLeft will return a number (bytes) indicating how much space    *}
  640. {*  remains in the selected buffer.  The INPUT buffer is checked if <IO> is *}
  641. {*  (I), and the output buffer is interrogated when <IO> is (O).  Any other *}
  642. {*  "action code" will return a result of 0.  Use this function when it is  *}
  643. {*  important to avoid program delays due to calls to output procedures or  *}
  644. {*  to prioritize the reception of data (to prevent overflows).             *}
  645. {*                                                                          *}
  646. {****************************************************************************}
  647.  
  648. Function ComBufferLeft(ComPort:Byte; IO:Char) : Word;
  649.  
  650. Begin
  651.   ComBufferLeft := 0;
  652.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  653.   IO := Upcase(IO);
  654.  
  655.   If IO = 'I' Then
  656.     If C_InHead[ComPort] >= C_InTail[ComPort] Then
  657.       ComBufferLeft := C_InSize[ComPort]-(C_InHead[ComPort]-C_InTail[ComPort])
  658.     Else
  659.       ComBufferLeft := C_InTail[ComPort]-C_InHead[ComPort];
  660.  
  661.   If IO = 'O' Then
  662.     If C_OutHead[ComPort] >= C_OutTail[ComPort] Then
  663.       ComBufferLeft := C_OutHead[ComPort]-C_OutTail[ComPort]
  664.     Else
  665.       ComBufferLeft := C_OutSize[ComPort]-(C_OutTail[ComPort]-C_OutHead[ComPort]);
  666. End;
  667.  
  668. {****************************************************************************}
  669. {*                                                                          *}
  670. {*  Procedure ComWaitForClear(ComPort:Byte)                                 *}
  671. {*                                                                          *}
  672. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  673. {*                    Exits immediately if out of range or port unopened.   *}
  674. {*                                                                          *}
  675. {*  A call to ComWaitForClear will stop processing until the selected out-  *}
  676. {*  put buffer is completely emptied.  Typically used just before a call    *}
  677. {*  to the CloseCom procedure to prevent premature cut-off of messages in   *}
  678. {*  transit.                                                                *}
  679. {*                                                                          *}
  680. {****************************************************************************}
  681.  
  682. Procedure ComWaitForClear(ComPort:Byte);
  683.  
  684. Var
  685.   Empty : Boolean;
  686.  
  687. Begin
  688.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  689.   Repeat
  690.     Empty := (C_Status[ComPort] And $04) = $04;
  691.     Empty := Empty And ((Port[C_PortAddr[ComPort]+C_IER] And $02) = $00);
  692.   Until Empty;
  693. End;
  694.  
  695. {****************************************************************************}
  696. {*                                                                          *}
  697. {*  Procedure ComWrite(ComPort:Byte; St:String)                             *}
  698. {*                                                                          *}
  699. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  700. {*                    Exits immediately if out of range or port unopened.   *}
  701. {*  St:String     ->  String to send                                        *}
  702. {*                                                                          *}
  703. {*  Sends string <St> out communications port <ComPort>.                    *}
  704. {*                                                                          *}
  705. {****************************************************************************}
  706.  
  707. Procedure ComWrite(ComPort:Byte; St:String);
  708.  
  709. Var
  710.   X : Byte;
  711.  
  712. Begin
  713.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  714.  
  715.   For X := 1 To Length(St) Do
  716.     ComWriteChW(ComPort,St[X]);
  717. End;
  718.  
  719. {****************************************************************************}
  720. {*                                                                          *}
  721. {*  Procedure ComWriteln(ComPort:Byte; St:String);                          *}
  722. {*                                                                          *}
  723. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  724. {*                    Exits immediately if out of range or port unopened.   *}
  725. {*  St:String     ->  String to send                                        *}
  726. {*                                                                          *}
  727. {*  Sends string <St> with a CR and LF appended.                            *}
  728. {*                                                                          *}
  729. {****************************************************************************}
  730.  
  731. Procedure ComWriteln(ComPort:Byte; St:String);
  732.  
  733. Var
  734.   X : Byte;
  735.  
  736. Begin
  737.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  738.  
  739.   For X := 1 To Length(St) Do
  740.     ComWriteChW(ComPort,St[X]);
  741.   ComWriteChW(ComPort,#13);
  742.   ComWriteChW(ComPort,#10);
  743. End;
  744.  
  745. {****************************************************************************}
  746. {*                                                                          *}
  747. {*  Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);         *}
  748. {*                                                                          *}
  749. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  750. {*                    Exits immediately if out of range or port unopened.   *}
  751. {*  St:String     ->  String to send                                        *}
  752. {*  Dly:Word      ->  Time, in milliseconds, to delay between each char.    *}
  753. {*                                                                          *}
  754. {*  ComWriteWithDelay will send string <St> to port <ComPort>, delaying     *}
  755. {*  for <Dly> milliseconds between each character.  Useful for systems that *}
  756. {*  cannot keep up with transmissions sent at full speed.                   *}
  757. {*                                                                          *}
  758. {****************************************************************************}
  759.  
  760. Procedure ComWriteWithDelay(ComPort:Byte; St:String; Dly:Word);
  761.  
  762. Var
  763.   X : Byte;
  764.  
  765. Begin
  766.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  767.  
  768.   ComWaitForClear(ComPort);
  769.   For X := 1 To Length(St) Do
  770.     Begin
  771.       ComWriteChW(ComPort,St[X]);
  772.       ComWaitForClear(ComPort);
  773.       Delay(Dly);
  774.     End;
  775. End;
  776.  
  777. {****************************************************************************}
  778. {*                                                                          *}
  779. {* Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean)*}
  780. {*                                                                          *}
  781. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom).                         *}
  782. {*                    Exits immediately if out of range or port unopened.   *}
  783. {*  St:String     <-  Edited string from remote                             *}
  784. {*  Size:Byte;    ->  Maximum allowable length of input                     *}
  785. {*  Echo:Boolean; ->  Set TRUE to echo received characters                  *}
  786. {*                                                                          *}
  787. {*  ComReadln is the remote equivalent of the standard Pascal READLN pro-   *}
  788. {*  cedure with some enhancements.  ComReadln will accept an entry of up to *}
  789. {*  40 printable ASCII characters, supporting ^H and ^X editing commands.   *}
  790. {*  Echo-back of the entry (for full-duplex operation) is optional.  All    *}
  791. {*  control characters, as well as non-ASCII (8th bit set) characters are   *}
  792. {*  stripped.  If <Echo> is enabled, ASCII BEL (^G) characters are sent     *}
  793. {*  when erroneous characters are intercepted.  Upon receipt of a ^M (CR),  *}
  794. {*  the procedure is terminated and the final string result returned.       *}
  795. {*                                                                          *}
  796. {****************************************************************************}
  797.  
  798. Procedure ComReadln(ComPort:Byte; Var St:String; Size:Byte; Echo:Boolean);
  799.  
  800. Var
  801.   Len,X : Byte;
  802.   Ch : Char;
  803.   Done : Boolean;
  804.  
  805. Begin
  806.   St := '';
  807.   If (ComPort<1) Or (ComPort>C_MaxCom) Or (Not C_PortOpen[ComPort]) Then Exit;
  808.  
  809.   Done := False;
  810.   Repeat
  811.     Len := Length(St);
  812.     Ch := Chr(Ord(ComReadChW(ComPort)) And $7F);
  813.  
  814.     Case Ch Of
  815.       ^H : If Len > 0 Then
  816.              Begin
  817.                Dec(Len);
  818.                St[0] := Chr(Len);
  819.                If Echo Then ComWrite(ComPort,#8#32#8);
  820.              End
  821.            Else
  822.              ComWriteChW(ComPort,^G);
  823.       ^M : Begin
  824.              Done := True;
  825.              If Echo Then ComWrite(ComPort,#13#10);
  826.            End;
  827.       ^X : Begin
  828.              St := '';
  829.              If Len = 0 Then ComWriteCh(ComPort,^G);
  830.              If Echo Then
  831.                For X := 1 to Len Do
  832.                  ComWrite(ComPort,#8#32#8);
  833.            End;
  834.       #32..#127 : If Len < Size Then
  835.                     Begin
  836.                       Inc(Len);
  837.                       St[Len] := Ch;
  838.                       St[0] := Chr(Len);
  839.                       If Echo Then ComWriteChW(ComPort,Ch);
  840.                     End
  841.                   Else
  842.                     If Echo Then ComWriteChW(ComPort,^G);
  843.     Else
  844.       If Echo Then ComWriteChW(ComPort,^G)
  845.     End;
  846.  
  847.   Until Done;
  848. End;
  849.  
  850. {****************************************************************************}
  851. {*                                                                          *}
  852. {*  Function ComExist(ComPort:Byte) : Boolean                               *}
  853. {*                                                                          *}
  854. {*  ComPort:Byte  ->  Port # to use (1 - C_MaxCom)                          *}
  855. {*                    Returns FALSE if out of range                         *}
  856. {*  Returns TRUE if hardware for selected port is detected & tests OK       *}
  857. {*                                                                          *}
  858. {*  Function ComExist performs a high-speed short loopback test on the      *}
  859. {*  selected port to determine if it indeed exists.  Use this function      *}
  860. {*  before attempts to OPEN a port for I/O (although this function is       *}
  861. {*  called by OpenCom to prevent such an occurance).                        *}
  862. {*  NOTE!  Although pains are taken to preserve the 8250 state before the   *}
  863. {*  port test takes place, it is nonetheless recommended that this function *}
  864. {*  NOT be called while a port is actually OPEN.  Doing so may cause the    *}
  865. {*  port to behave erratically.                                             *}
  866. {*                                                                          *}
  867. {****************************************************************************}
  868.  
  869. Function ComExist(ComPort:Byte) : Boolean;
  870.  
  871. Const
  872.   TestByte1 : Byte = $0F;
  873.   TestByte2 : Byte = $F1;
  874.  
  875. Var
  876.   P : Word;
  877.   M,L,B1,B2 : Byte;
  878.  
  879. Begin
  880.   ComExist := False;
  881.   If (ComPort<1) Or (ComPort>C_MaxPort) Then Exit;
  882.  
  883.   P := C_PortAddr[ComPort];
  884.   M := Port[P+C_MCR];                            { Save MCR }
  885.   L := Port[P+C_LCR];                            { Save LCR }
  886.   Port[P+C_MCR] := $10;                          { Enable loopback mode }
  887.   Port[P+C_LCR] := $80;                          { Enable divisor latch mode }
  888.   B1 := Port[P];                                 { Save current baud rate }
  889.   B2 := Port[P+1];
  890.   Port[P] := 4;                                  { Set baud rate to 28000 }
  891.   Port[P+1] := 0;
  892.   Port[P+C_LCR] := $03;                          { Transmit mode 28000:8N1 }
  893.  
  894.   Port[P] := TestByte1;                          { Test byte #1 }
  895.   Delay(20);                                     { Wait a bit for loopback }
  896.   If Port[P] <> TestByte1 Then Exit;             { Exit w/error if not echoed }
  897.   Port[P] := TestByte2;                          { Test byte #2 }
  898.   Delay(20);                                     { Wait a bit for loopback }
  899.   If Port[P] <> TestByte2 Then Exit;             { Exit w/error if not echoed }
  900.  
  901.   ComExist := True;                              { Test passed: Port exists }
  902.   Port[P+C_LCR] := $80;                          { Restore baud rate }
  903.   Port[P] := B1;
  904.   Port[P+1] := B2;
  905.   Port[P+C_LCR] := L;                            { Restore parameters }
  906.   Port[P+C_MCR] := M;                            { Restore control lines }
  907. End;
  908.  
  909. {****************************************************************************}
  910. {*                                                                          *}
  911. {*  Function ComTrueBaud(Baud:Longint) : Real                               *}
  912. {*                                                                          *}
  913. {*  Baud:Longint  ->  User baud rate to test.                               *}
  914. {*                    Should be between C_MinBaud and C_MaxBaud.            *}
  915. {*  Returns the actual baud rate based on the accuracy of the 8250 divider. *}
  916. {*                                                                          *}
  917. {*  The ASYNC11 communications package allows the programmer to select ANY  *}
  918. {*  baud rate, not just those that are predefined by the BIOS or other      *}
  919. {*  agency.  Since the 8250 uses a divider/counter chain to generate it's   *}
  920. {*  baud clock, many non-standard baud rates can be generated.  However,    *}
  921. {*  the binary counter/divider is not always capable of generating the      *}
  922. {*  EXACT baud rate desired by a user.  This function, when passed a valid  *}
  923. {*  baud rate, will return the ACTUAL baud rate that will be generated.     *}
  924. {*  The baud rate is based on a 8250 input clock rate of 1.73728 MHz.       *}
  925. {*                                                                          *}
  926. {****************************************************************************}
  927.  
  928. Function ComTrueBaud(Baud:Longint) : Real;
  929.  
  930. Var
  931.   X : Real;
  932.   Y : Word;
  933.  
  934. Begin
  935.   X := Baud;
  936.   If X < C_MinBaud Then X := C_MinBaud;
  937.   If X > C_MaxBaud Then X := C_MaxBaud;
  938.   ComTrueBaud := 115200 / Round($900/(X/50));
  939. End;
  940.  
  941. {****************************************************************************}
  942. {*                                                                          *}
  943. {*  Procedure ComParams(ComPort:Byte; Baud:Longint;                         *}
  944. {*                      WordSize:Byte; Parity:Char; StopBits:Byte);         *}
  945. {*                                                                          *}
  946. {*  ComPort:Byte   ->  Port # to initialize.  Must be (1 - C_MaxCom)        *}
  947. {*                     Procedure aborted if port # invalid or unopened.     *}
  948. {*  Baud:Longint   ->  Desired baud rate.  Should be (C_MinBaud - C_MaxBaud)*}
  949. {*                     C_MinBaud or C_MaxBaud used if out of range.         *}
  950. {*  WordSize:Byte  ->  Word size, in bits.  Must be 5 - 8 bits.             *}
  951. {*                     8-bit word used if out of range.                     *}
  952. {*  Parity:Char    ->  Parity classification.                               *}
  953. {*                     May be N)one, E)ven, O)dd, M)ark or S)pace.          *}
  954. {*                     N)one selected if classification unknown.            *}
  955. {*  StopBits:Byte  ->  # of stop bits to pad character with.  Range (1-2)   *}
  956. {*                     1 stop bit used if out of range.                     *}
  957. {*                                                                          *}
  958. {*  ComParams is used to configure an OPEN'ed port for the desired comm-    *}
  959. {*  unications parameters, namely baud rate, word size, parity form and     *}
  960. {*  # of stop bits.  A call to this procedure will set up the port approp-  *}
  961. {*  riately, as well as assert the DTR, RTS and OUT2 control lines and      *}
  962. {*  clear all buffers.                                                      *}
  963. {*                                                                          *}
  964. {****************************************************************************}
  965.  
  966. Procedure ComParams(ComPort:Byte; Baud:LongInt; WordSize:Byte; Parity:Char; StopBits:Byte);
  967.  
  968. Const
  969.   C_Stopbit1    = $00;                 { Bit masks for parity, stopbits }
  970.   C_Stopbit2    = $04;
  971.   C_NoParity    = $00;
  972.   C_OddParity   = $08;
  973.   C_EvenParity  = $18;
  974.   C_MarkParity  = $28;
  975.   C_SpaceParity = $38;
  976.  
  977. Var
  978.   X : Real;
  979.   Y,P : Word;
  980.   DivMSB,DivLSB : Byte;
  981.   WS,SB,PTY : Byte;
  982.  
  983. Begin
  984.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  985.  
  986.   Inline($FA);
  987.   P := C_PortAddr[ComPort];
  988.  
  989.   { Calculate baud rate divisors }
  990.  
  991.   X := Baud;
  992.   If X < C_MinBaud Then X := C_MinBaud;
  993.   If X > C_MaxBaud Then X := C_MaxBaud;
  994.   Y := Round($900/(X/50));
  995.   DivMSB := Hi(Y);
  996.   DivLSB := Lo(Y);
  997.  
  998.   { Determine parity mask }
  999.   { Default if unknown: No parity }
  1000.  
  1001.   Case UpCase(Parity) Of
  1002.     'N' : PTY := C_NoParity;
  1003.     'E' : PTY := C_EvenParity;
  1004.     'O' : PTY := C_OddParity;
  1005.     'M' : PTY := C_MarkParity;
  1006.     'S' : PTY := C_SpaceParity;
  1007.   Else
  1008.     PTY := C_NoParity;
  1009.   End;
  1010.  
  1011.   { Determine stop-bit mask }
  1012.   { Default if out of range: 1 Stop bit }
  1013.  
  1014.   Case StopBits Of
  1015.     1 : SB := C_StopBit1;
  1016.     2 : SB := C_StopBit2;
  1017.   Else
  1018.     SB := C_StopBit1;
  1019.   End;
  1020.  
  1021.   { Determine word-size mask }
  1022.   { Default if out of range: 8 bit word size }
  1023.  
  1024.   If (WordSize >= 5) And (WordSize <= 8) Then
  1025.     WS := WordSize - 5
  1026.   Else
  1027.     WS := 3;
  1028.  
  1029.   { Initialize line-control register }
  1030.  
  1031.   Y := Port[P] + Port[P+C_LSR];
  1032.   Port[P+C_LCR] := WS + SB + PTY;
  1033.  
  1034.   { Initialize baud rate divisor latches }
  1035.  
  1036.   Port[P+C_LCR] := Port[P+C_LCR] Or $80;
  1037.   Port[P] := DivLSB;
  1038.   Port[P+1] := DivMSB;
  1039.   Port[P+C_LCR] := Port[P+C_LCR] And $7F;
  1040.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1041.  
  1042.   { Assert RS323 control lines (DTR,RTS,OUT2) & exit }
  1043.  
  1044.   Port[P+C_MCR] := $0B;
  1045.   ClearCom(ComPort,'B');
  1046.   Inline($FB);
  1047. End;
  1048.  
  1049. {****************************************************************************}
  1050. {*                                                                          *}
  1051. {*  Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word):Boolean *}
  1052. {*                                                                          *}
  1053. {*  ComPort:Byte        ->  Port # to OPEN (1 - C_MaxCom)                   *}
  1054. {*                          Request will fail if out of range or port OPEN  *}
  1055. {*  InBufferSize:Word   ->  Requested size of input (receive) buffer        *}
  1056. {*  OutBufferSize:Word  ->  Requested size of output (transmit) buffer      *}
  1057. {*  Returns success/fail status of OPEN request (TRUE if OPEN successful)   *}
  1058. {*                                                                          *}
  1059. {*  OpenCom must be called before any activity (other than existence check, *}
  1060. {*  see the ComExist function) takes place.  OpenCom initializes the        *}
  1061. {*  interrupt drivers and serial communications hardware for the selected   *}
  1062. {*  port, preparing it for I/O.  Memory for buffers is allocated on the     *}
  1063. {*  Pascal "heap", thus freeing data-segment memory for larger more data-   *}
  1064. {*  intensive programs.  Once a port has been OPENed, a call to ComParams   *}
  1065. {*  should be made to set up communications parameters (baud rate, parity   *}
  1066. {*  and the like).  Once this is done, I/O can take place on the port.      *}
  1067. {*  OpenCom will return a TRUE value if the opening procedure was success-  *}
  1068. {*  ful, or FALSE if it is not.                                             *}
  1069. {*                                                                          *}
  1070. {****************************************************************************}
  1071.  
  1072. Function OpenCom(ComPort:Byte; InBufferSize,OutBufferSize:Word) : Boolean;
  1073.  
  1074. Var
  1075.   TempVec : Pointer;
  1076.   P : Word;
  1077.   IntLn,X : Byte;
  1078.  
  1079. Begin
  1080.   { Ensure that port was not previously open }
  1081.  
  1082.   OpenCom := False;
  1083.   If (ComPort<1) Or (ComPort>C_MaxPort) Or C_PortOpen[ComPort] Then Exit;
  1084.   If Not ComExist(ComPort) Then Exit;
  1085.  
  1086.   { Clear any pending activity from 8250 interrupt queue }
  1087.  
  1088.   Inline($FA);
  1089.   P := C_PortAddr[ComPort];
  1090.   Port[P+C_IER] := $0D;
  1091.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1092.  
  1093.   { Set up interrupt vectors & 8259 PIC }
  1094.  
  1095.   IntLn := C_PortInt[ComPort];
  1096.   GetIntVec(8+IntLn,TempVec);
  1097.   If C_OldINTVec[IntLn] <> TempVec Then
  1098.     Begin
  1099.       C_OldINTVec[IntLn] := TempVec;
  1100.       SetIntVec(8+IntLn,@Int_Handler);
  1101.       Port[$21] := Port[$21] And (($01 SHL IntLn) XOR $FF);
  1102.       X := Port[$21];
  1103.     End;
  1104.  
  1105.   { Allocate memory for I/O buffers }
  1106.  
  1107.   C_InSize[ComPort] := InBufferSize;
  1108.   C_OutSize[ComPort] := OutBufferSize;
  1109.   GetMem(C_InBufPtr[ComPort],InBufferSize);
  1110.   GetMem(C_OutBufPtr[ComPort],OutBufferSize);
  1111.  
  1112.   { Set up default parameters for port }
  1113.  
  1114.   C_RTSOn[ComPort] := InBufferSize - 2;
  1115.   C_RTSOff[ComPort] := InBufferSize - 1;
  1116.   C_StartChar[ComPort] := ^Q;
  1117.   C_StopChar[ComPort] := ^S;
  1118.   C_PortOpen[ComPort] := True;
  1119.   OpenCom := True;
  1120.  
  1121.   Inline($FB);
  1122. End;
  1123.  
  1124. {****************************************************************************}
  1125. {*                                                                          *}
  1126. {*  Procedure CloseCom(ComPort:Byte)                                        *}
  1127. {*                                                                          *}
  1128. {*  ComPort:Byte  ->  Port # to close                                       *}
  1129. {*                    Request ignored if port closed or out of range.       *}
  1130. {*                                                                          *}
  1131. {*  CloseCom will un-link the interrupt drivers for a port, deallocate it's *}
  1132. {*  buffers and drop the DTR and RTS signal lines for a port opened with    *}
  1133. {*  the OpenCom function.  It should be called before exiting your program  *}
  1134. {*  to ensure that the port is properly shut down.                          *}
  1135. {*  NOTE:  CloseCom shuts down a communications channel IMMEDIATELY,        *}
  1136. {*         even if there is data present in the input or output buffers.    *}
  1137. {*         Therefore, you may wish to call the ComWaitForClear procedure    *}
  1138. {*         before closing the ports.                                        *}
  1139. {*                                                                          *}
  1140. {****************************************************************************}
  1141.  
  1142. Procedure CloseCom(ComPort:Byte);
  1143.  
  1144. Var
  1145.   ClosePort : Boolean;
  1146.   P,IntLn,X : Word;
  1147.  
  1148. Begin
  1149.   If (ComPort<1) Or (ComPort>C_MaxPort) Or (Not C_PortOpen[ComPort]) Then Exit;
  1150.  
  1151.   { Drop RS232 control lines (DTR,RTS,OUT2) and reset 8250 interrupt mode }
  1152.  
  1153.   Inline($FA);
  1154.   P := C_PortAddr[ComPort];
  1155.   Port[P+C_MCR] := 0;
  1156.   Port[P+C_IER] := 0;
  1157.   C_PortOpen[ComPort] := False;
  1158.  
  1159.   { Reset INT vectors & 8259 PIC if all COMs on selected INT are closed }
  1160.  
  1161.   IntLn := C_PortInt[ComPort];
  1162.   ClosePort := True;
  1163.   For X := 1 To C_MaxCom Do
  1164.     If C_PortOpen[X] And (C_PortInt[X] = IntLn) Then
  1165.       ClosePort := False;
  1166.  
  1167.   If ClosePort Then
  1168.     Begin
  1169.       Port[$21] := Port[$21] Or ($01 SHR IntLn);
  1170.       X := Port[$21];
  1171.       SetIntVec(8+IntLn,C_OldINTVec[IntLn]);
  1172.     End;
  1173.   X := Port[P] + Port[P+C_LSR] + Port[P+C_MSR] + Port[P+C_IIR];
  1174.  
  1175.   { Deallocate buffers }
  1176.  
  1177.   FreeMem(C_InBufPtr[ComPort],C_InSize[ComPort]);
  1178.   FreeMem(C_OutBufPtr[ComPort],C_OutSize[ComPort]);
  1179.   Inline($FB);
  1180. End;
  1181.  
  1182. {****************************************************************************}
  1183. {*                                                                          *}
  1184. {*  Procedure CloseAllComs                                                  *}
  1185. {*                                                                          *}
  1186. {*  CloseAllComs will CLOSE all currently OPENed ports.  See the CloseCom   *}
  1187. {*  procedure description for more details.                                 *}
  1188. {*                                                                          *}
  1189. {****************************************************************************}
  1190.  
  1191. Procedure CloseAllComs;
  1192.  
  1193. Var
  1194.   X : Byte;
  1195.  
  1196. Begin
  1197.   For X := 1 To C_MaxCom Do
  1198.     If C_PortOpen[X] Then
  1199.       CloseCom(X);
  1200. End;
  1201.  
  1202. {****************************************************************************}
  1203. {*                                                                          *}
  1204. {*                        UNIT Initialization Code                          *}
  1205. {*                                                                          *}
  1206. {****************************************************************************}
  1207.  
  1208. Begin
  1209.   For x := 1 to C_MaxPort Do
  1210.     Begin
  1211.       C_PortOpen[x] := False;
  1212.       C_InBufPtr[x] := Nil;
  1213.       C_OutBufPtr[x] := Nil;
  1214.       C_OldIntVec[x] := Nil;
  1215.       C_InHead[x] := 0;
  1216.       C_OutHead[x] := 0;
  1217.       C_InTail[x] := 0;
  1218.       C_OutTail[x] := 0;
  1219.       C_InSize[x] := 0;
  1220.       C_OutSize[x] := 0;
  1221.       C_RTSOn[x] := 0;
  1222.       C_RTSOff[x] := 0;
  1223.       C_StartChar[x] := ^Q;
  1224.       C_StopChar[x] := ^S;
  1225.       C_Status[x] := 5;
  1226.       C_Ctrl[x] := 0;
  1227.       C_XL3Ptr[x] := 0;
  1228.       Port[C_PortAddr[x]+C_MCR] := $00;
  1229.     End;
  1230.    writeln ('Async.PAS')
  1231. End.
  1232.